package chen.web.widget.vote;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;

import chen.web.BusinessException;
import chen.web.DataSourceProvider;
import chen.web.MyContext;
import chen.web.MyContextProvider;
import chen.web.user.Account;
import chen.web.util.DateInt;
import chen.web.widget.Widget;

public class VoteManagerImpl implements VoteManager{

	private SimpleJdbcTemplate simpleJdbcTemplate = new SimpleJdbcTemplate(DataSourceProvider.getDataSource());
	private JdbcTemplate  jdbcTemplate  = new JdbcTemplate(DataSourceProvider.getDataSource());
	
	private static final String SQL_14 = "delete from web_vote where vote_id = ?";
	private static final String SQL_15 = "delete from web_vote_option where vote_id = ?";
	private static final String SQL_16 = "delete from web_voter_info where vote_id = ?";
	@Override
	public void delete(Widget widget) {
		// TODO Auto-generated method stub
		Vote vote = (Vote)widget;
		simpleJdbcTemplate.update(SQL_14, vote.getId());
		simpleJdbcTemplate.update(SQL_15, vote.getId());
		simpleJdbcTemplate.update(SQL_16, vote.getId());	
	}
	
	private static final String SQL_12 = "select t1.vote_id, vote_title, vote_dateline, vote_deadline, vote_optionalQuantity, vote_publicVoters, vote_flag, option_id, option_content, option_count from web_vote t1 right join (SELECT option_id, vote_id, option_content, option_count, option_order FROM web_vote_option where vote_id = ?)t2 on t1.vote_id = t2.vote_id order by option_order asc";
	@Override
	public Vote get(int id) {
		Vote vote = null;
		try{
			vote = simpleJdbcTemplate.queryForObject(SQL_12, new VoteMapper(), id);	
		}catch(EmptyResultDataAccessException e){
			//do nothing
		}

		return vote;
	}

	private static final String SQL_29 = "select * from web_voter_info where option_id = ?";
	@Override
	public List<VoterInfo> getVotersInfo(VoteOption option) {
		// TODO Auto-generated method stub
		if(!option.getBelongVote().isPublicVoters()){
			throw new BusinessException(BusinessException.Vote_Can_Not_Public_Voters);
		}
		
		List<VoterInfo> infos = simpleJdbcTemplate.query(SQL_29, new VoterInfoMapper(), option.getId());
		return infos;
	}

	private static final String SQL_10 = "insert into web_vote(vote_title, vote_dateline, vote_deadline, vote_optionalQuantity, vote_publicVoters, vote_flag) values(?,?,?,?,?,?)";
	private static final String SQL_11 = "insert into web_vote_option(vote_id, option_content, option_order) values(?,?,?)";
	@Override
	public Vote add(final Widget widget) {
		final Vote vote = (Vote)widget;
		// TODO Auto-generated method stub
		String[] options = vote.getOptionsContent();
		if(options.length < 2){
			throw new BusinessException(BusinessException.Vote_At_Least_Two_Option);
		}
		KeyHolder keyHolder = new GeneratedKeyHolder();
		jdbcTemplate.update(new PreparedStatementCreator(){
			@Override
			public PreparedStatement createPreparedStatement(Connection conn)
					throws SQLException {
				// TODO Auto-generated method stub
				PreparedStatement ps = conn.prepareStatement(SQL_10, PreparedStatement.RETURN_GENERATED_KEYS);
				ps.setString(1, vote.getTitle());
				ps.setInt(2, DateInt.transform(vote.getDateline()));
				ps.setInt(3, DateInt.transform(vote.getDeadline()));
				ps.setInt(4, vote.getOptionalQuantity());
				ps.setBoolean(5, vote.isPublicVoters());
				ps.setInt(6, vote.getFlag());
				return ps;
			}
		
		}, keyHolder);
		int id = keyHolder.getKey().intValue();
		vote.setId(id);
		
		List<Object[]> batch = new ArrayList<Object[]>();
		for(int i=0; i<options.length; i++){
			Object[] args = new Object[]{
					vote.getId(),
					options[i],
					i+1
			};
			batch.add(args);
		}
		simpleJdbcTemplate.batchUpdate(SQL_11, batch);
		
		return vote;
	}

	private static final String SQL_26 = "insert into web_voter_info(option_id, vote_id, info_accountId, info_nickname, info_ip, info_uuid, info_date) values(?,?,?,?,?,?,?)";
	private static final String SQL_27 = "update web_vote_option set option_count = option_count + 1 where option_id = ?"; 
	private void _vote(VoteOption option, VoterInfo info){
		simpleJdbcTemplate.update(SQL_26, option.getId(), option.getBelongVote().getId(), info.getAccountId(), info.getNickname(), info.getIp(), info.getUuid(), DateInt.transform(info.getDate()));
		simpleJdbcTemplate.update(SQL_27, option.getId());
	}
	
	@Override
	public void vote(VoteOption option) {
		// TODO Auto-generated method stub
		if(hasVoted(option.getBelongVote())){
			throw new BusinessException(BusinessException.Vote_Has_Voted);
		}
		VoterInfo info = new VoterInfo();
		MyContext context = MyContextProvider.getMyContext();
		Account acc  = context.getAccount();
		info.setAccountId(acc.getId());
		info.setNickname(acc.getNickname());
		info.setDate(new Date());
		info.setIp(context.getIp());
		info.setUuid(context.getUuid());
		_vote(option, info);
	}
	
	@Override
	public void vote(VoteOption... options) {
		// TODO Auto-generated method stub
		int length = options.length;
		if(length == 0){
			throw new IllegalArgumentException();
		}
		
		//确定所选项都是来是同一投票项目
		for(VoteOption option : options){
			if(option == null || option.getBelongVote().getId() != option.getBelongVote().getId()){
				throw new IllegalArgumentException();
			}
		}
		
		Vote belong = options[0].getBelongVote();
		//超过可选数
		if(length > belong.getOptionalQuantity()){
			throw new BusinessException(BusinessException.Vote_Outnumber_Optional_Quantity);
		}

		//判断是已经投过票
		if(hasVoted(belong)){
			throw new BusinessException(BusinessException.Vote_Has_Voted);
		}
		
		VoterInfo info = new VoterInfo();
		MyContext context = MyContextProvider.getMyContext();
		Account acc  = context.getAccount();
		info.setAccountId(acc.getId());
		info.setNickname(acc.getNickname());
		info.setDate(new Date());
		info.setIp(context.getIp());
		info.setUuid(context.getUuid());
		for(VoteOption option : options){
			_vote(option, info);
		}
	}
	
	private static final String SQL_58 = "select count(*) from web_voter_info where vote_id = ? and info_accountId = ?";
	private static final String SQL_59 = "select count(*) from web_voter_info where vote_id = ? and info_uuid = ?";
	@Override
	public boolean hasVoted(Vote vote) {
		// TODO Auto-generated method stub
		MyContext context = MyContextProvider.getMyContext();
		Account acc  = context.getAccount();
		int accountId = acc.getId();
		//非访客公用帐号
		if(accountId != 1){
			int n = simpleJdbcTemplate.queryForInt(SQL_58, vote.getId(), accountId);
			if(n > 0){
				return true;
			}
			return false;
		}
		//访客公用帐号,用判断uuid判断是否投过票
		String uuid = context.getUuid();
		int n = simpleJdbcTemplate.queryForInt(SQL_59, vote.getId(), uuid);
		if(n > 0){
			return true;
		}
		return false;
	}

	private static final class VoterInfoMapper implements RowMapper<VoterInfo>{

		@Override
		public VoterInfo mapRow(ResultSet rs, int rowNum) throws SQLException {
			// TODO Auto-generated method stub
			VoterInfo info = new VoterInfo();
			info.setAccountId(rs.getInt("info_accountId"));
			info.setNickname(rs.getString("info_nickname"));
			info.setIp(rs.getString("info_ip"));
			info.setUuid(rs.getString("info_uuid"));
			info.setDate(DateInt.transform(rs.getInt("info_date")));
			return info;
		}
		
	}
	
	private static final class VoteMapper implements RowMapper<Vote>{
		@Override
		public Vote mapRow(ResultSet rs, int rowNum) throws SQLException {
			// TODO Auto-generated method stub
				Vote vote = new Vote(rs.getInt("vote_id"));
				vote.setTitle(rs.getString("vote_title"));
				vote.setDateline(DateInt.transform(rs.getInt("vote_dateline")));
				vote.setDeadline(DateInt.transform(rs.getInt("vote_deadline")));
				vote.setFlag(rs.getInt("vote_flag"));
				vote.setOptionalQuantity(rs.getInt("vote_optionalQuantity"));
				vote.setPublicVoters(rs.getBoolean("vote_publicVoters"));
				VoteOption option = new VoteOption();
				option.setId(rs.getInt("option_id"));
				option.setCount(rs.getInt("option_count"));
				option.setContent(rs.getString("option_content"));
				option.setBelongVote(vote);
				vote.addOption(option);
				while(rs.next()){
					VoteOption option1 = new VoteOption();
					option1.setId(rs.getInt("option_id"));
					option1.setCount(rs.getInt("option_count"));
					option1.setContent(rs.getString("option_content"));
					option1.setBelongVote(vote);
					vote.addOption(option1);
				}
			return vote;
		}
	}

	private static final String SQL_20 = "update web_vote set vote_title=?, vote_dateline=?, vote_dateline=?, vote_optionalQuantity=?, vote_publicVoters=?, vote_flag=? where vote_id=?";
	@Override
	public Vote update(Widget widget) {
		// TODO Auto-generated method stub
		Vote vote = (Vote)widget;
		simpleJdbcTemplate.update(SQL_20, vote.getTitle(), DateInt.transform(vote.getDateline()), DateInt.transform(vote.getDeadline()), vote.getOptionalQuantity(), vote.isPublicVoters(), vote.getFlag(), vote.getId());
		return vote;
	}

	@Override
	public boolean scope(Class<? extends Widget> clazz) {
		// TODO Auto-generated method stub
		if(Vote.class.equals(clazz))
			return true;
		return false;
	}


}
